package com.yonyou.sto.modules.ims.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.GsonBuilder;
import com.yonyou.sto.common.api.CommonResult;
import com.yonyou.sto.common.domain.OpenBillBuilder;
import com.yonyou.sto.domain.InvoiceStatusEnums;
import com.yonyou.sto.domain.ManualStatusEnums;
import com.yonyou.sto.modules.ims.dto.ImsPartySelectParam;
import com.yonyou.sto.modules.ims.dto.ManualDto;
import com.yonyou.sto.modules.ims.mapper.ImsManualInvoiceMapper;
import com.yonyou.sto.modules.ims.mapper.ImsTaxItemMapper;
import com.yonyou.sto.modules.ims.model.*;
import com.yonyou.sto.modules.ims.service.*;
import com.yonyou.sto.modules.ums.model.UmsAdmin;
import com.yonyou.sto.modules.ums.service.UmsAdminRoleRelationService;
import com.yonyou.sto.modules.ums.service.UmsAdminService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.Principal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author aegon
 * @since 2020-10-20
 */
@Service
public class ImsManualInvoiceServiceImpl extends ServiceImpl<ImsManualInvoiceMapper, ImsManualInvoice> implements ImsManualInvoiceService {

    private static final Logger LOGGER = LoggerFactory.getLogger(OpenBillServiceImpl.class);

    @Value("${yonyoucloud.app_id}")
    private String APP_ID;

    @Value("${yonyoucloud.domain}")
    private String DOMAIN;

    @Value("${yonyoucloud.split_url}")
    private String SPLIT_URL;

    @Value("${yonyoucloud.callback_url}")
    private String CALLBACK_URL;

    @Value("${yonyoucloud.callback_email}")
    private String CALLBACK_EMAIL;

    @Value("${yonyoucloud.callback_phone}")
    private String CALLBACK_PHONE;

    @Resource
    private ImsInvoiceItemService itemService;

    @Resource
    private UmsAdminService adminService;

    @Resource
    private UmsAdminRoleRelationService roleRelationService;

    @Resource
    private ImsPartyAdminRelationService relationService;

    @Resource
    private ImsPartyService partyService;

    @Resource
    private ImsBuyerService buyerService;

    @Resource
    private ImsBillService billService;

    @Resource
    private OpenBillBuilder openBillBuilder;

    @Resource
    private ImsPartyAdminRelationService imsPartyAdminRelationService;
    @Resource
    private ImsBuyerService imsBuyerService;

    @Resource
    private ImsTaxItemMapper imsTaxItemMapper;

    @Override
    public CommonResult add(Principal principal, ManualDto dto) {
        ImsManualInvoice manual = new ImsManualInvoice();
        BeanUtil.copyProperties(dto, manual);
        String billSn = createBillSn();
        manual.setBillSn(billSn);

        List<ImsInvoiceItem> collect = new ArrayList<>();
        for (ImsInvoiceItem col : dto.getInvoiceItems()) {
            col.setBillSn(billSn);

            ImsTaxItem tax = imsTaxItemMapper.getTaxItemById(col.getTaxItemId());
            col.setProductSn(tax.getTaxItemCategoryCode());

            col.setCreateTime(DateUtil.format(new Date(), DatePattern.NORM_DATE_FORMAT));
            // 用户填价税合计 则 含税单价=价税合计/数量  总价=价税合计/税率+1  单价=含税单价/税率+1
            BigDecimal price = col.getTaxAmount().divide(BigDecimal.valueOf(col.getProductQuantity()), RoundingMode.CEILING);
            col.setTaxPrice(price);
            col.setProductAmount(col.getTaxAmount().divide(col.getTaxRate().add(BigDecimal.ONE), RoundingMode.CEILING));
            col.setProductPrice(price.divide(col.getTaxRate().add(BigDecimal.ONE), RoundingMode.CEILING));
            col.setStatus(InvoiceStatusEnums.NOT.getCode());

            collect.add(col);
        }

        manual.setPayAmount(collect.stream().map(ImsInvoiceItem::getProductAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
        manual.setTaxAmount(collect.stream().map(ImsInvoiceItem::getTaxAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
        manual.setStatus(ManualStatusEnums.NOT_APPROVAL.getCode());

        UmsAdmin umsAdmin = adminService.getAdminByUsername(principal.getName());
        manual.setCreateUsername(umsAdmin.getUsername());
        manual.setCreateNickname(umsAdmin.getNickName());
        manual.setCreateTime(new Date());
        boolean boo = save(manual);

        if (boo) {
            List<ImsInvoiceItem> items = collect.stream().peek(col -> col.setManualId(manual.getId())).collect(Collectors.toList());
            itemService.saveBatch(items);
            return CommonResult.success("新增成功");
        }
        return CommonResult.failed();
    }

    @Override
    public Page<ImsManualInvoice> list(String username, Integer pageSize, Integer pageNum, String billSn, String partyName, String buyerName, Integer status) {
        UmsAdmin umsAdmin = adminService.getAdminByUsername(username);
//        List<Long> roleIds = roleRelationService.getRoleIdsByAdminId(umsAdmin.getId());
//        List<Long> partyIds = relationService.getPartyIdsByAdminId(umsAdmin.getId());

        Page<ImsManualInvoice> page = new Page<>(pageNum, pageSize);
        QueryWrapper<ImsManualInvoice> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<ImsManualInvoice> lambda = wrapper.lambda();


        if (StrUtil.isNotEmpty(billSn)) lambda.like(ImsManualInvoice::getBillSn, billSn);

        if (StrUtil.isNotEmpty(partyName)) lambda.like(ImsManualInvoice::getPartyName, partyName);

        if (StrUtil.isNotEmpty(buyerName)) lambda.like(ImsManualInvoice::getBuyerName, buyerName);

        if (status != null) lambda.eq(ImsManualInvoice::getStatus, status);

//        if (!roleIds.contains(5L) && CollUtil.isNotEmpty(roleIds)) {
//            List<ImsParty> parties = partyService.listByIds(partyIds);
//            lambda.and(la -> la.eq(ImsManualInvoice::getCreateUsername, username).or().in(ImsManualInvoice::getSellerSn, parties.stream().map(ImsParty::getSellerSn).collect(Collectors.toList())));
//        }
        List<Long> partyIds = imsPartyAdminRelationService.getPartyIdsByAdminId(umsAdmin.getId());
       if (partyIds.size()>0){
           CommonResult reslut = partyService.getPartyByPartyId(partyIds);
           if (reslut.getCode()==200){
               List<ImsParty> party = (List<ImsParty>) reslut.getData();
               lambda.in(ImsManualInvoice::getPartyName,party.stream().map(ImsParty::getPartyName).collect(Collectors.toList()));
           }
       }else {

       }

        lambda.orderByDesc(ImsManualInvoice::getCreateTime);

        System.out.println(lambda.getSqlSelect());

        return page(page, wrapper);
    }

    @Override
    public Page<ImsManualInvoice> verifyList(String username, Integer pageSize, Integer pageNum, String billSn, String partyName, String buyerName, Integer status) {

        // 当前登录用户->组织->单据  管理员5看全部
        //权限控制，当前登录人对应的公司与当前列表的销售组织相同并且当前登录人是该组织下的复核人
        UmsAdmin umsAdmin = adminService.getAdminByUsername(username);
        List<ImsParty> parties = partyService.getPartyByVerifyUsername(umsAdmin.getUsername());

        List<String> seller = parties.stream().map(ImsParty::getSellerSn).collect(Collectors.toList());

        List<String> roleIds = roleRelationService.getRoleIdsByAdminId(umsAdmin.getId());

        Page<ImsManualInvoice> page = new Page<>(pageNum, pageSize);
        QueryWrapper<ImsManualInvoice> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<ImsManualInvoice> lambda = wrapper.lambda();

        // 如果当前用户不是组织的复核人
        if (seller.size() == 0) {
            lambda.eq(ImsManualInvoice::getStatus, 9999);
        }
        if (!roleIds.contains(5L) && seller.size() != 0) {
//        if (seller.size() != 0) {
            lambda.in(ImsManualInvoice::getSellerSn, seller);
        }
        if (StrUtil.isNotEmpty(billSn)) lambda.like(ImsManualInvoice::getBillSn, billSn);

        if (StrUtil.isNotEmpty(partyName)) lambda.like(ImsManualInvoice::getSellerName, partyName);

         if (parties.size()>0) lambda.in(ImsManualInvoice::getPartyName, parties.get(0).getPartyName());

        if (StrUtil.isNotEmpty(buyerName)) lambda.like(ImsManualInvoice::getBuyerName, buyerName);

        if (status != null) {
            lambda.eq(ImsManualInvoice::getStatus, status);
        } else {
            lambda.in(ImsManualInvoice::getStatus, 1, 2);
        }

        lambda.orderByDesc(ImsManualInvoice::getCreateTime);

        return page(page, wrapper);
    }

    @Override
    public CommonResult openBill(Principal principal, List<String> ids) {
        try {

            List<ImsManualInvoice> manuals = baseMapper.selectBatchIds(ids);
            long count = manuals.stream().filter(i -> i.getStatus() != ManualStatusEnums.NOT_OPEN.getCode()).count();
            if (count > 0) return CommonResult.failed("存在非待开票状态的票据,不能开票.");

            List<ImsInvoiceItem> items = itemService.listByManualIds(ids);
            long count1 = items.stream().filter(item -> item.getTaxRate() == null).count();
            if (count1 > 0) return CommonResult.failed("存在未选择税率的明细,不能开票.");

            GsonBuilder builder = new GsonBuilder();
            List<Object> datas = new ArrayList<>();
            List<Object> urls = new ArrayList<>();
            List<Object> emails = new ArrayList<>();
            List<Object> phones = new ArrayList<>();

            UmsAdmin umsAdmin = adminService.getAdminByUsername(principal.getName());

            manuals.forEach(manual -> {
                ImsBuyer buyer = buyerService.getBuyerByBuyerTaxSn(manual.getBuyerTaxSn());
                ImsParty party = partyService.getPartyBySellerSn(manual.getSellerSn());

                String serial = OpenBillBuilder.createSerialNumber();

                Map<String, Object> data = new HashMap<>();
                data.put("FPQQLSH", serial);
                data.put("FPLX", manual.getBillType());
                data.put("BZ", manual.getNote());
                data.put("XSF_NSRSBH", party.getSellerTaxSn());
                data.put("XSF_MC", party.getSellerName());
                data.put("XSF_DZDH", party.getSellerAddress() + party.getSellerPhone());
//                data.put("XSF_YHZH", party.getSellerBankAccount());

                data.put("GMF_NSRSBH", buyer.getBuyerTaxSn());
                data.put("GMF_MC", buyer.getBuyerName());
                data.put("GMF_DZDH", buyer.getBuyerAddress() + buyer.getBuyerPhone());
                data.put("GMF_YHZH", buyer.getBuyerBankAccount());
                data.put("ORGCODE", party.getPartySn());
                data.put("KPR", umsAdmin.getNickName());

                List<ImsInvoiceItem> items1 = items.stream().filter(em -> em.getManualId().equals(manual.getId())).collect(Collectors.toList());
                BigDecimal reduce = items1.stream().map(ImsInvoiceItem::getTaxAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                data.put("JSHJ", reduce);
                data.put("items", openBillBuilder.buildItems(items1, 1));
                datas.add(data);

                Map<String, Object> url = new HashMap<>();
                url.put("fpqqlsh", serial);
                url.put("url", CALLBACK_URL);
                urls.add(url);

                Map<String, Object> phone = new HashMap<>();
                phone.put("fpqqlsh", serial);
                phone.put("address", CALLBACK_PHONE);
                phone.put("title", "电子发票 : " + serial);
                phone.put("content", manual.getBillContent());
                phones.add(phone);

                Map<String, Object> email = new HashMap<>();
                email.put("fpqqlsh", serial);
                email.put("address", CALLBACK_EMAIL);
                phone.put("title", "电子发票 : " + serial);
                phone.put("content", manual.getBillContent());
                emails.add(email);

                manual.setStatus(ManualStatusEnums.OPEN.getCode());

            });

            Map<String, String> paramsMap = new HashMap<>();
            paramsMap.put("requestdatas", builder.create().toJson(datas));
            paramsMap.put("email", builder.create().toJson(emails));
            paramsMap.put("sms", builder.create().toJson(phones));
            paramsMap.put("url", builder.create().toJson(urls));
            paramsMap.put("autoAudit", "true");

            LOGGER.info("手工开蓝票接口参数报文:   " + paramsMap);

            Map resultMap = openBillBuilder.callInvoiceApply(DOMAIN + SPLIT_URL + APP_ID, paramsMap);
            if ("0000".equals(resultMap.get("code"))) {

                // 修改单据状态 添加发票
                this.updateBatchById(manuals);
                billService.splitAddBill(null, (List<Map<String, Object>>) resultMap.get("datas"));
                return CommonResult.success(resultMap.get("msg"));
            } else {
                return CommonResult.failed(resultMap.get("msg").toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return CommonResult.failed("开票失败,请检查单据信息");
        }
    }

    @Override
    public boolean updateStatusBySerial(int code, String serial) {
        return baseMapper.updateStatusBySerial(code, serial);
    }

    @Override
    public CommonResult<ManualDto> info(String id) {
        ManualDto dto = new ManualDto();
        ImsManualInvoice byId = getById(id);
        BeanUtil.copyProperties(byId, dto);

        ImsParty party = partyService.getPartyBySellerSn(byId.getSellerSn());
        BeanUtil.copyProperties(party, dto);

        ImsBuyer buyer = buyerService.getBuyerByBuyerTaxSn(byId.getBuyerTaxSn());
        BeanUtil.copyProperties(buyer, dto);

        List<ImsInvoiceItem> items = itemService.listByManualIds(Collections.singletonList(id));
        dto.setInvoiceItems(items);
        dto.setManualId(id);

        return CommonResult.success(dto);
    }

    @Override
    public CommonResult edit(ManualDto dto) {
        ImsManualInvoice manual = new ImsManualInvoice();
        BeanUtil.copyProperties(dto, manual);

        List<ImsInvoiceItem> collect = new ArrayList<>();
        for (ImsInvoiceItem col : dto.getInvoiceItems()) {

            ImsTaxItem tax = imsTaxItemMapper.getTaxItemById(col.getTaxItemId());
            col.setProductSn(tax.getTaxItemCategoryCode());

            // 用户填价税合计 则 含税单价=价税合计/数量  总价=价税合计/税率+1  单价=含税单价/税率+1
            BigDecimal price = col.getTaxAmount().divide(BigDecimal.valueOf(col.getProductQuantity()), RoundingMode.CEILING);
            col.setTaxPrice(price);
            col.setProductAmount(col.getTaxAmount().divide(col.getTaxRate().add(BigDecimal.ONE), RoundingMode.CEILING));
            col.setProductPrice(price.divide(col.getTaxRate().add(BigDecimal.ONE), RoundingMode.CEILING));
            col.setStatus(InvoiceStatusEnums.NOT.getCode());

            collect.add(col);
        }

        manual.setPayAmount(collect.stream().map(ImsInvoiceItem::getProductAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
        manual.setTaxAmount(collect.stream().map(ImsInvoiceItem::getTaxAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
        manual.setId(dto.getManualId());

        updateById(manual);
        itemService.updateBatchById(collect);
        return CommonResult.success("编辑成功");
    }

    @Override
    public CommonResult verify(ManualDto dto) {
        ImsManualInvoice manual = new ImsManualInvoice();
        BeanUtil.copyProperties(dto, manual);

        manual.setRejectTime(new Date());
        manual.setId(dto.getManualId());
        boolean b = updateById(manual);
        if (b) return CommonResult.success("审批成功");
        return CommonResult.failed();
    }


    public static String createBillSn() {
        String format = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN);

        String model = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        char[] m = model.toCharArray();

        StringBuilder sb = new StringBuilder("SG");
        StringBuilder randomCode = new StringBuilder();
        for (int j = 0; j < 4; j++) {
            char c = m[(int) (Math.random() * 35)];
            randomCode.append(c);
        }
        sb.append(format);
        sb.append(randomCode);
        return sb.toString();
    }

}
